import { pages, subPackages, tabBar } from '@/pages.json'
import { isMpWeixin } from './platform'
import { debounce, DebounceSettings } from 'lodash-es'

const getLastPage = () => {
  // getCurrentPages() 至少有1个元素，所以不再额外判断
  // const lastPage = getCurrentPages().at(-1)
  // 上面那个在低版本安卓中打包会报错，所以改用下面这个【虽然我加了 src/interceptions/prototype.ts，但依然报错】
  const pages = getCurrentPages()
  return pages[pages.length - 1]
}

/** 判断当前页面是否是 tabbar 页  */
export const getIsTabbar = () => {
  if (!tabBar) {
    return false
  }
  if (!tabBar.list.length) {
    // 通常有 tabBar 的话，list 不能有空，且至少有2个元素，这里其实不用处理
    return false
  }
  const lastPage = getLastPage()
  const currPath = lastPage.route
  return !!tabBar.list.find((e) => e.pagePath === currPath)
}

/**
 * 获取当前页面路由的 path 路径和 redirectPath 路径
 * path 如 '/pages/login/index'
 * redirectPath 如 '/pages/demo/base/route-interceptor'
 */
export const currRoute = () => {
  const lastPage = getLastPage()
  const currRoute = (lastPage as any).$page
  // console.log('lastPage.$page:', currRoute)
  // console.log('lastPage.$page.fullpath:', currRoute.fullPath)
  // console.log('lastPage.$page.options:', currRoute.options)
  // console.log('lastPage.options:', (lastPage as any).options)
  // 经过多端测试，只有 fullPath 靠谱，其他都不靠谱
  const { fullPath } = currRoute as { fullPath: string }
  // console.log(fullPath)
  // eg: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor (小程序)
  // eg: /pages/login/index?redirect=%2Fpages%2Froute-interceptor%2Findex%3Fname%3Dfeige%26age%3D30(h5)
  return getUrlObj(fullPath)
}

const ensureDecodeURIComponent = (url: string) => {
  if (url.startsWith('%')) {
    return ensureDecodeURIComponent(decodeURIComponent(url))
  }
  return url
}
/**
 * 解析 url 得到 path 和 query
 * 比如输入url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
 * 输出: {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}}
 */
export const getUrlObj = (url: string) => {
  const [path, queryStr] = url.split('?')
  // console.log(path, queryStr)

  if (!queryStr) {
    return {
      path,
      query: {},
    }
  }
  const query: Record<string, string> = {}
  queryStr.split('&').forEach((item) => {
    const [key, value] = item.split('=')
    // console.log(key, value)
    query[key] = ensureDecodeURIComponent(value) // 这里需要统一 decodeURIComponent 一下，可以兼容h5和微信y
  })
  return { path, query }
}
/**
 * 得到所有的需要登录的 pages，包括主包和分包的
 * 这里设计得通用一点，可以传递 key 作为判断依据，默认是 needLogin, 与 route-block 配对使用
 * 如果没有传 key，则表示所有的 pages，如果传递了 key, 则表示通过 key 过滤
 */
export const getAllPages = (key = 'needLogin') => {
  // 这里处理主包
  const mainPages = [
    ...pages
      .filter((page) => !key || page[key])
      .map((page) => ({
        ...page,
        path: `/${page.path}`,
      })),
  ]
  // 这里处理分包
  const subPages: any[] = []
  subPackages.forEach((subPageObj) => {
    // console.log(subPageObj)
    const { root } = subPageObj

    subPageObj.pages
      .filter((page) => !key || page[key])
      .forEach((page: { path: string } & Record<string, any>) => {
        subPages.push({
          ...page,
          path: `/${root}/${page.path}`,
        })
      })
  })
  const result = [...mainPages, ...subPages]
  // console.log(`getAllPages by ${key} result: `, result)
  return result
}

/**
 * 得到所有的需要登录的 pages，包括主包和分包的
 * 只得到 path 数组
 */
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((page) => page.path)

/**
 * 得到所有的需要登录的 pages，包括主包和分包的
 * 只得到 path 数组
 */
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path)

/**
 * 根据微信小程序当前环境，判断应该获取的 baseUrl
 */
export const getEnvBaseUrl = () => {
  // 请求基准地址
  let baseUrl = import.meta.env.VITE_SERVER_BASEURL

  // 微信小程序端环境区分
  if (isMpWeixin) {
    const {
      miniProgram: { envVersion },
    } = uni.getAccountInfoSync()

    switch (envVersion) {
      case 'develop':
        baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_DEVELOP || baseUrl
        break
      case 'trial':
        baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_TRIAL || baseUrl
        break
      case 'release':
        baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_RELEASE || baseUrl
        break
    }
  }

  return baseUrl
}

/**
 * 根据微信小程序当前环境，判断应该获取的 UPLOAD_BASEURL
 */
export const getEnvBaseUploadUrl = () => {
  // 请求基准地址
  let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL

  // 微信小程序端环境区分
  if (isMpWeixin) {
    const {
      miniProgram: { envVersion },
    } = uni.getAccountInfoSync()

    switch (envVersion) {
      case 'develop':
        baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_DEVELOP || baseUploadUrl
        break
      case 'trial':
        baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_TRIAL || baseUploadUrl
        break
      case 'release':
        baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_RELEASE || baseUploadUrl
        break
    }
  }

  return baseUploadUrl
}

/**
 * 防抖函数封装
 * @param func 需要防抖的目标函数
 * @param wait 等待时间（毫秒）
 * @param options Lodash 防抖配置项
 * @returns 包装后的防抖函数（包含取消方法）
 */
export function createDebounceFunc<T extends (...args: any[]) => any>(
  func: T,
  wait: number,
  options?: DebounceSettings,
): {
  execute: (...args: Parameters<T>) => ReturnType<T> | undefined
  cancel: () => void
  flush: () => ReturnType<T> | undefined
} {
  const debounced = debounce(func, wait, options)

  return {
    // 执行防抖函数
    execute: debounced,
    // 取消待执行的防抖调用
    cancel: debounced.cancel,
    // 立即执行当前待处理的调用
    flush: debounced.flush,
  }
}

/**
 * 格式化日期时间
 * @param date 可接收Date实例或时间戳（number）
 * @param formatStr 格式化字符串，默认：'YYYY-MM-DD HH:mm:ss'
 * @returns 格式化后的日期字符串
 *
 * 支持格式：
 * YYYY - 四位年份
 * MM - 两位月份（01-12）
 * DD - 两位天数（01-31）
 * HH - 24小时制小时数（00-23）
 * mm - 分钟数（00-59）
 * ss - 秒数（00-59）
 *
 * 示例：
 * // 使用示例
// console.log(formatDate()) // 当前时间的默认格式
// console.log(formatDate(1689302400000, 'YYYY/MM/DD HH:mm')) // 时间戳格式化
// console.log(formatDate(new Date(), 'YYYY年MM月DD日')) // 自定义格式
 * formatDate(new Date(), 'YYYY年MM月DD日 HH:mm:ss') // 2023年08月15日 14:30:45
 */
export function formatDate(
  date: string | Date | number = new Date(),
  formatStr: string = 'YYYY-MM-DD HH:mm:ss',
): string {
  if (typeof date === 'string') {
    try {
      date = new Date(date)
    } catch (error) {
      throw new Error('Invalid date string')
    }
  }
  // 统一处理日期参数
  const d = typeof date === 'number' ? new Date(date) : date

  // 提取日期各部分值
  const year = d.getFullYear()
  const month = d.getMonth() + 1 // 月份从0开始需加1
  const day = d.getDate()
  const hours = d.getHours()
  const minutes = d.getMinutes()
  const seconds = d.getSeconds()

  // 补零函数（确保两位数显示）
  const padZero = (num: number) => num.toString().padStart(2, '0')

  // 使用对象存储格式化值便于替换
  const formatMap: { [key: string]: string } = {
    YYYY: year.toString(),
    MM: padZero(month),
    DD: padZero(day),
    HH: padZero(hours),
    mm: padZero(minutes),
    ss: padZero(seconds),
  }

  // 使用正则替换所有格式标记
  return formatStr.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => formatMap[match])
}

/**
 * 金额数值标准化函数
 * @param value 输入值（支持 number/string/null/undefined）
 * @param options 配置项
 * @returns 格式化的两位小数金额字符串
 */
export function formatMoney(
  value: number | string | null | undefined,
  options?: {
    padZero?: boolean // 是否强制补零（默认true）
    roundMode?: 'floor' | 'ceil' | 'round' // 舍入方式（默认四舍五入）
    safeParse?: boolean // 是否启用安全解析（默认true）
  },
): string {
  // 参数合并默认值
  const { padZero = true, roundMode = 'round', safeParse = true } = options || {}

  // 安全解析逻辑
  let num = 0
  if (safeParse) {
    if (typeof value === 'string') {
      value = value.replace(/[^\d.-]/g, '') // 去除非数字字符
    }
    num = Number(value) || 0
  } else {
    num = Number(value)
  }

  // 舍入计算
  let processed: number
  switch (roundMode) {
    case 'floor':
      processed = Math.floor(num * 100) / 100
      break
    case 'ceil':
      processed = Math.ceil(num * 100) / 100
      break
    default:
      processed = Math.round(num * 100) / 100
  }

  // 格式化为两位小数
  const parts = processed.toFixed(2).split('.')
  if (!padZero && parts[1] === '00') {
    return parts[0] // 不补零
  }
  return processed.toFixed(2)
}
